package items;

import roborally.EnergyAmount;
import roborally.EnergyUnit;
import elements.IEnergyHolder;
import elements.Robot;
import be.kuleuven.cs.som.annotate.Basic;
import be.kuleuven.cs.som.annotate.Immutable;

/**
 * @invar	| this.isLegalEnergy(this.getEnergy())
 * @invar	| this.getBoard()==null || this.isTerminated() 
 * 			|	|| this.getPosition()!=null 
 * 			|	|| for one robot in this.getBoard().<Robot>getElementsOfType(Robot.class): robot.getItems().contains(this)
 * 
 * @version	3.0
 * @author 	Lies Tambeur 	r0264469	2Bcwsbbh
 * @author	Eline Vanrykel	r0264543	2Bcwselt
 *
 */
public class Battery extends Item implements IEnergyHolder{
	
	private EnergyAmount energy;
	
	/**
	 * @invar	|  MAX_ENERGY.getAmount() > 0
	 */
	private final static EnergyAmount MAX_ENERGY = new EnergyAmount(5000,EnergyUnit.WATTSECONDS);
	
	/**
	 * @return	| result == MAX_ENERGY
	 */
	@Basic @Immutable
	public static EnergyAmount getMaxEnergy(){
		return MAX_ENERGY;
	}
	
	/**
	 * @param 	energy
	 * @param 	weight
	 * @effect	| super(weight)
	 * @effect	| setEnergy(energy)
	 */
	public Battery(EnergyAmount energy, int weight){
		super(weight);
		this.setEnergy(energy);
	}
	
	/**
	 * @effect	| this(new EnergyAmount(500,EnergyUnit.WATTSECONDS),500)
	 */
	public Battery(){
		this(new EnergyAmount(500,EnergyUnit.WATTSECONDS),500);
	}
	
	/**
	 * @param	energy
	 * @pre		| this.isLegalEnergy(energy)
	 * @post	| new.getEnergy() == energy
	 */
	public void setEnergy(EnergyAmount energy){ 
		assert this.isLegalEnergy(energy);
		this.energy = energy;
	}
	
	/**
	 * @param 	energy
	 * @return	| (!energy.isSmallerThan(new EnergyAmount())) && (!Battery.getMaxEnergy().isSmallerThan(energy)) && energy!=null
	 */
	@Override
	public boolean isLegalEnergy(EnergyAmount energy){
		return (!energy.isSmallerThan(new EnergyAmount())) && (!Battery.getMaxEnergy().isSmallerThan(energy)) && energy!=null;
	}
	
	/**
	 * @return	| result == this.energy
	 */
	@Override @Basic
	public EnergyAmount getEnergy(){
		return this.energy;
	}
	
	/**
	 * @param	amount
	 * @effect	| this.setEnergy(this.getEnergy().addAndReturn(amount))
	 */
	@Override
	public void recharge(EnergyAmount amount) {
		assert !new EnergyAmount().isSmallerThan(amount);
		this.setEnergy(this.getEnergy().addAndReturn(amount));
	}
	
	
	/**
	 * @return	| result == "BATTERY with energy "+this.getEnergy()+", and weight "+this.getWeight()+"g"
	 */
	public String toString() {
		return "BATTERY with energy "+this.getEnergy()+", and weight "+this.getWeight()+"g";
	}

	/**
	 * @post	| new.getEnergy() == minimum(this.getEnergy().addAndReturn(500,EnergyUnit.WATTSECONDS), this.getMaxEnergy())
	 */
	@Override
	public void hit() {
		EnergyAmount amount = this.getEnergy().addAndReturn(new EnergyAmount(500,EnergyUnit.WATTSECONDS));
		if(!amount.isSmallerThan(getMaxEnergy())){
			amount = getMaxEnergy();
		}
		this.recharge(amount);
	}
	
	/**
	 * @param	robot
	 * @effect	| robot.transferEnergy(this, minimum( this.getEnergy, Robot.getMaxEnergy()-robot.getEnergy() ) );
	 * @effect	| this.terminate()
	 * @post	| !robot.getItems().contains(this)
	 */
	@Override
	public void used(Robot robot) {
		EnergyAmount amount = new EnergyAmount();
		if(robot.isLegalEnergy(robot.getEnergy().addAndReturn(this.getEnergy()))){
			amount = this.getEnergy();
		}
		else{
			amount = robot.getMaxEnergy().subtractAndReturn(robot.getEnergy());
		}
		robot.transferEnergy(this, amount);
		robot.getItems().remove(this);
		this.terminate();
		
	}
	
	/**
	 * @param	energy
	 * @pre		| !energy.isSmallerThan(new EnergyAmount())
	 * @effect	| this.setEnergy(this.getEnergy().subtractAndReturn(amount)) 
	 */
	@Override
	public void decrease(EnergyAmount energy) {
		assert !energy.isSmallerThan(new EnergyAmount());
		this.setEnergy(this.getEnergy().subtractAndReturn(energy));
	}

}
